package erfgame.core.graphics.renderer.render;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import java.awt.image.BufferedImage;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.logging.Logger;

import org.apache.batik.ext.awt.RenderingHintsKeyExt;


import erfgame.core.CompassDirection;
import erfgame.core.PointAndAngle;
import erfgame.core.entity.Entity;
import erfgame.core.entity.State;
import erfgame.core.graphics.renderer.animation.AnimationCycle;
import erfgame.core.graphics.renderer.animation.StateAnimationCycleFactory;

public class ImageEntityAnimationFactoryProxy implements EntityAnimationFactory {

	private static final Logger log = Logger.getLogger(ImageEntityAnimationFactoryProxy.class.getName());
	
	private EntityAnimationFactory proxied;
	private StateAnimationCycleFactory animationCycleFactory;
	private String[] knownPointNames;
	
	public ImageEntityAnimationFactoryProxy(
			EntityAnimationFactory proxied, 
			String[] knownPointNames,
			StateAnimationCycleFactory animationCycleFactory ) {
		this.proxied = proxied;
		this.knownPointNames = knownPointNames;
		this.animationCycleFactory = animationCycleFactory;
	}
	
	public Animation getAnimation(
			Entity entity, 
			State state,
			CompassDirection orientation, 
			double rotation) throws Exception {
		Animation animation = proxied.getAnimation(entity, state, orientation, rotation);
		
//		int[] argb = new int[maxSize.width];

		AnimationCycle animationCycle = animationCycleFactory.getAnimationCycle(state, entity.getEntityType());
		if( animationCycle != null ) {
			int[] timings = animationCycle.getStepTimes();
			float total = animationCycle.getCycleTime();
			float[] frameTimes = new float[timings.length];
			
			Render[] frames = new Render[timings.length];
			int timingCount = 0;
			for( int i=0; i<frames.length; i++ ) {
				float progress = ((float)timingCount)/total;
				Render render = animation.getFrame(progress);
				timingCount += timings[i];
				Render imageRender = toImageRender( render, i );
				frames[i] = imageRender;
				frameTimes[i] = progress;
			}
			return new IncrementalAnimation(frameTimes, frames);
		} else {
			Render render = animation.getFrame(0);
			Render imageRender = toImageRender( render, 0 );
			return new StaticAnimation( imageRender );
		}
	}

	
	private Render toImageRender( Render render, int frame ) {
		
		Dimension size = render.getSize();
		BufferedImage image = new BufferedImage(
				size.width, 
				size.height, 
				BufferedImage.TYPE_INT_ARGB
		);
		Graphics2D g = (Graphics2D)image.getGraphics();
		// TODO these should probably be configurable
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
		g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY );
		g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
		// gets around warning from batik (can also just turn off warning, which might be faster and is mostly harmless)
		g.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, new WeakReference<BufferedImage>(image)); 
		
		render.render(g, 0, 0);
//			g.setColor(Color.red);
//			g.drawString(Integer.toString(i), 0, size.height);
//			g.drawRect(0, 0, (int)(size.width * progress), size.height);
//			for( int y=size.height; y>0; ) {
//				y--;
//				image.setRGB(0, y,size.width, 1, argb, 0, size.width);
//			}
//		g.setColor( Color.red );
//		String frameString = Integer.toString(frame); 
//		FontMetrics fm = g.getFontMetrics();
//		g.drawString( frameString, (size.width - fm.stringWidth(frameString))/2, fm.getAscent() );
		
		g.dispose();
		HashMap<String, PointAndAngle> points = new HashMap<String, PointAndAngle>( knownPointNames.length );
		for( int j=knownPointNames.length; j>0; ) {
			j--;
			String knownPointName = knownPointNames[j];
			PointAndAngle point = render.getPoint(knownPointName);
			if( point != null ) {
				points.put(knownPointName, point);
			}
		}
		ImageRender imageRender = new ImageRender(image, points);
		return imageRender;
	}
}
